/*
Copyright (C) Ariff Ehsan, Abdul Hadi Fikri

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*  Author : Ariff Ehsan
 *           Abdul Hadi Fikri
 *  Date   : June 22, 2009
 */


#include <system.h>
#include <serial0/ports/atmega16/atmega16_usart0.h>


BOOL atmega16_usart0_send_busy;
uint8_t atmega16_usart0_pend_data;

void (*atmega16_usart0_sendDone)(void);
void (*atmega16_usart0_receive)(uint8_t);


/* prototype function */
void ATMEGA16_USART0_defaultSendDone(void);
void ATMEGA16_USART0_defaultReceive(uint8_t);



/********************************************************************************************/
/*                                  Clients Function Call                                   */
/********************************************************************************************/
void ATMEGA16_USART0_init(void) {
	
	uint16_t baud = MYUBRR;
	
	atmega16_usart0_send_busy = FALSE;

	atmega16_usart0_sendDone = ATMEGA16_USART0_defaultSendDone;
	atmega16_usart0_receive = ATMEGA16_USART0_defaultReceive;

	/* Set baud rate */
	UBRRH = (unsigned char)(baud>>8);
	UBRRL = (unsigned char)baud;

	/* Enable receiver and transmitter and interrupt*/
	UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<TXCIE)|(1<<RXCIE);
 
	/* Set frame format: 8data, 1stop bit */
	UCSRC = (3<<UCSZ0);
}

void ATMEGA16_USART0_reg(void (*sendDone)(void), void (*receive)(uint8_t data)) {
	
	if (sendDone != NULL)
		atmega16_usart0_sendDone = sendDone;
	
	if (receive != NULL)
		atmega16_usart0_receive = receive;
	
}

error_t ATMEGA16_USART0_send(uint8_t data) {
	
	if (atmega16_usart0_send_busy) {
		return EBUSY;
	}

	atmega16_usart0_send_busy = TRUE;
  
	if (!( UCSRA & (1<<UDRE) )) {
		atmega16_usart0_pend_data = data;
    
		// enable UDRE interrupt
		UCSRB |= (1<<UDRIE);

		return SUCCESS;
	}

	UDR = data;
	
	return SUCCESS;
}

/********************************************************************************************/
/*                                 Internal Function Call                                   */
/********************************************************************************************/
void ATMEGA16_USART0_defaultSendDone(void) {
}

void ATMEGA16_USART0_defaultReceive(uint8_t data) {
}
/********************************************************************************************/
/*                              HW/SW Interrupt Function Call                               */
/********************************************************************************************/
/**
 *  ISR UDRE
 */  
ISR (USART_UDRE_vect ) {

	// disable UDRE interrupt
	CLR_BIT(UCSRB, UDRIE);
	UDR = atmega16_usart0_pend_data;
}


/**
 *  ISR TRANSMIT
 */
ISR (USART_TXC_vect) {

	atmega16_usart0_send_busy = FALSE;
	(*atmega16_usart0_sendDone)();
}


/**
 *  ISR RECEIVE
 */
ISR (USART_RXC_vect) {

	uint8_t data = UDR;
	(*atmega16_usart0_receive)(data);
}



